package com.favccxx.search.domain.calcite.connection;

import com.favccxx.search.domain.calcite.CalciteModel;
import com.favccxx.search.domain.calcite.CalciteModelService;
import com.favccxx.search.infrastructure.util.jackson.JacksonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author favccxx
 */
@Slf4j
@Service
public class CalciteConnectionService {

    private static final Pattern DB_NAME_PATTERN = Pattern.compile("\\s+\"(\\S*?)\"\\.\"\\S*?\"");

    @Autowired
    CalciteModelService calciteModelService;

    public Connection getConnection() {
        try {
            CalciteModel model = calciteModelService.getCalciteModel();
            String connectStr = JacksonUtil.toJsonString(model);
            Properties info = new Properties();
            info.put("model", "inline:" + connectStr);
            Connection connection = DriverManager.getConnection("jdbc:calcite:" + connectStr, info);
            return connection;
        } catch (SQLException e) {
            log.error("Calcite connect failed", e);
            return null;
        }

    }


    public Connection getConnection(String sql) {
        try {
            Set<String> dataSourceCodes = extractDbNames(sql);
            CalciteModel model = calciteModelService.getCalciteModel(dataSourceCodes);
            String connectStr = JacksonUtil.toJsonString(model);
            Properties info = new Properties();
            info.put("model", "inline:" + connectStr);
            Connection connection = DriverManager.getConnection("jdbc:calcite:" + connectStr, info);
            return connection;
        } catch (Exception e) {
            log.error("Calcite getConnection failed", e);
        }
        return null;
    }


    /**
     * Get database names by sql
     *
     * @param sql
     * @return
     */
    private Set<String> extractDbNames(String sql) {
        Matcher matcher = DB_NAME_PATTERN.matcher(sql);
        HashSet<String> dbNames = new HashSet<>();
        while (matcher.find()) {
            dbNames.add(matcher.group(1));
        }
        return dbNames;
    }

}
